
import com.sun.opengl.util.Animator;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureData;
import com.sun.opengl.util.texture.TextureIO;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.media.opengl.DebugGL;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import java.awt.image.BufferedImage;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 *
 * @author cmolikl
 */
public class MeshDisplay implements GLEventListener, ChangeListener, ActionListener {

    private GLU glu;
    private Texture picTexture;
    private int value = 0;
    private int old_value = 0;
    private Animator anim;
    private BufferedImage img;
    private final float x_center = -27.0f;
    private final float y_center = 0.0f;
    private final float z_center = 0.0f;
    private final float a = 20.0f;
    private final int X_AXIS = 10;
    private final int Y_AXIS = 20;
    private final int Z_AXIS = 30;
    private int currentAxis;
    // Konstanty určující velikost obrázku
    private ImageDisplay imgDisplay;
    TextureData data;

    public MeshDisplay(Animator _anim) {
        anim = _anim;
        imgDisplay = new ImageDisplay();
    }

    private void setCamera(GL gl, GLU glu, float distance) {
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        float widthHeightRatio = (float) 800 / (float) 600;
        glu.gluPerspective(45, widthHeightRatio, 1, 1000);
        glu.gluLookAt(0, 0, 50, 0, 0, 0, 0, 1, 0);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public void init(GLAutoDrawable drawable) {
        drawable.setGL(new DebugGL(drawable.getGL()));
        final GL gl = drawable.getGL();
        gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glDepthFunc(GL.GL_LEQUAL);
        gl.glShadeModel(GL.GL_SMOOTH);
        gl.glClearColor(0f, 0f, 0f, 0f);
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
        glu = new GLU();
        img = imgDisplay.getCurrentImage();
        data = TextureIO.newTextureData(img, true);
        picTexture = TextureIO.newTexture(data);
        currentAxis = imgDisplay.getCurrentAxis();
    }

    private void drawPlane(GL gl) {
        gl.glBegin(GL.GL_QUADS);
        gl.glColor3f(1.0f, 1.0f, 0.0f);
        switch (currentAxis) {
            case (Z_AXIS):
                
                float[] frontUL = {x_center - a / 2, y_center + a / 2, z_center - value * 0.078f};
                float[] frontUR = {x_center + a / 2, y_center + a / 2, z_center - value * 0.078f};
                float[] frontLR = {x_center + a / 2, y_center - a / 2, z_center - value * 0.078f};
                float[] frontLL = {x_center - a / 2, y_center - a / 2, z_center - value * 0.078f};

                gl.glNormal3f(0.0f, 0.0f, 1.0f);
                gl.glVertex3fv(frontUR, 0);
                gl.glVertex3fv(frontUL, 0);
                gl.glVertex3fv(frontLL, 0);
                gl.glVertex3fv(frontLR, 0);
                break;
            case (X_AXIS):
                float[] frontUL2 = {x_center - a / 2 + value * 0.0785f, y_center + a / 2, z_center -a};
                float[] frontUR2 = {x_center - a / 2 + value * 0.0785f, y_center + a / 2, z_center};
                float[] frontLR2 = {x_center - a / 2 + value * 0.0785f, y_center - a / 2, z_center};
                float[] frontLL2 = {x_center - a / 2 + value * 0.0785f, y_center - a / 2, z_center -a };

                gl.glNormal3f(0.0f, 0.0f, 1.0f);
                gl.glVertex3fv(frontUR2, 0);
                gl.glVertex3fv(frontUL2, 0);
                gl.glVertex3fv(frontLL2, 0);
                gl.glVertex3fv(frontLR2, 0);
                break;  
            case (Y_AXIS):
                float[] frontUL3 = {x_center - a / 2 , y_center + a / 2 - value * 0.0785f, z_center};
                float[] frontUR3 = {x_center + a / 2 , y_center + a / 2 - value * 0.0785f, z_center};
                float[] frontLR3 = {x_center - a / 2 , y_center + a / 2 - value * 0.0785f, z_center-a};
                float[] frontLL3 = {x_center + a / 2 , y_center + a / 2 - value * 0.0785f, z_center-a};

                gl.glNormal3f(0.0f, 0.0f, 1.0f);
                gl.glVertex3fv(frontUR3, 0);
                gl.glVertex3fv(frontUL3, 0);
                gl.glVertex3fv(frontLR3, 0);
                gl.glVertex3fv(frontLL3, 0);
                break; 
        }
        gl.glEnd();
    }

    private void drawCube(GL gl) {
        gl.glColor3f(1.0f, 1.0f, 1.0f);
        gl.glBegin(GL.GL_LINE_LOOP);
        gl.glVertex3f(x_center - a / 2, y_center - a / 2, 0);
        gl.glVertex3f(x_center + a / 2, y_center - a / 2, 0);
        gl.glVertex3f(x_center + a / 2, y_center + a / 2, 0);
        gl.glVertex3f(x_center - a / 2, y_center + a / 2, 0);
        gl.glEnd();

        gl.glBegin(GL.GL_LINE_LOOP);
        gl.glVertex3f(x_center + a / 2, y_center - a / 2, 0);
        gl.glVertex3f(x_center + a / 2, y_center - a / 2, z_center - a);
        gl.glVertex3f(x_center + a / 2, y_center + a / 2, z_center - a);
        gl.glVertex3f(x_center + a / 2, y_center + a / 2, 0);
        gl.glEnd();

        gl.glBegin(GL.GL_LINE_LOOP);
        gl.glVertex3f(x_center + a / 2, y_center + a / 2, 0);
        gl.glVertex3f(x_center + a / 2, y_center + a / 2, z_center - a);
        gl.glVertex3f(x_center - a / 2, y_center + a / 2, z_center - a);
        gl.glVertex3f(x_center - a / 2, y_center + a / 2, 0);
        gl.glEnd();

        gl.glBegin(GL.GL_LINE_LOOP);
        gl.glVertex3f(x_center - a / 2, y_center - a / 2, 0);
        gl.glVertex3f(x_center - a / 2, y_center - a / 2, z_center - a);
        gl.glVertex3f(x_center - a / 2, y_center + a / 2, z_center - a);
        gl.glVertex3f(x_center - a / 2, y_center + a / 2, 0);
        gl.glEnd();

        gl.glBegin(GL.GL_LINE_LOOP);
        gl.glVertex3f(x_center + a / 2, y_center - a / 2, 0);
        gl.glVertex3f(x_center + a / 2, y_center - a / 2, z_center - a);
        gl.glVertex3f(x_center - a / 2, y_center - a / 2, z_center - a);
        gl.glVertex3f(x_center - a / 2, y_center - a / 2, 0);
        gl.glEnd();
    }

    private void drawCT(GL gl) {
        gl.glEnable(GL.GL_TEXTURE_2D);
        if (value != old_value) {
            data = TextureIO.newTextureData(img, true);
            picTexture.updateImage(data);
            old_value = value;
        }
        picTexture.bind();
        gl.glBegin(GL.GL_QUADS);
        final float[] frontUL = {-3.0f, 20.0f, 0.0f};
        final float[] frontUR = {37.0f, 20.0f, 0.0f};
        final float[] frontLR = {37.0f, -20.0f, 0.0f};
        final float[] frontLL = {-3.0f, -20.0f, 0.0f};
        gl.glNormal3f(0.0f, 0.0f, 1.0f);
        gl.glTexCoord2f(0.0f, 0.0f);
        gl.glVertex3fv(frontUR, 0);
        gl.glTexCoord2f(1.0f, 0.0f);
        gl.glVertex3fv(frontUL, 0);
        gl.glTexCoord2f(1.0f, 1.0f);
        gl.glVertex3fv(frontLL, 0);
        gl.glTexCoord2f(0.0f, 1.0f);
        gl.glVertex3fv(frontLR, 0);
        gl.glEnd();
        picTexture.disable();
    }

    public void display(GLAutoDrawable drawable) {
        final GL gl = drawable.getGL();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        setCamera(gl, glu, 25);
        //lights
        float SHINE_ALL_DIRECTIONS = 1;
        float[] lightPos = {0, 0, 20, SHINE_ALL_DIRECTIONS};
        float[] lightColorAmbient = {0.2f, 0.2f, 0.2f, 1f};
        float[] lightColorSpecular = {0.8f, 0.8f, 0.8f, 1f};
        gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPos, 0);
        gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, lightColorAmbient, 0);
        gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, lightColorSpecular, 0);
        gl.glEnable(GL.GL_LIGHT1);
        gl.glEnable(GL.GL_LIGHTING);

        // Material properties
        float[] rgba = {1f, 1f, 1f};
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, rgba, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, rgba, 0);
        gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 0.5f);
        gl.glScalef(0.65f, 0.65f, 0.65f);
        drawPlane(gl);
        drawCube(gl);
        drawCT(gl);
    }

    public void reshape(GLAutoDrawable glad, int i, int i1, int i2, int i3) {
    }

    public void displayChanged(GLAutoDrawable glad, boolean bln, boolean bln1) {
    }

    public void stateChanged(ChangeEvent e) {
        JSlider slider = (JSlider) e.getSource();
        value = slider.getValue();
        imgDisplay.generateImage(value);
        img = imgDisplay.getCurrentImage();
    }

    /**
     * Implementace rozhraní ActionListener volá se vždy když se změní hodnota v
     * menu. Na základě hodnoty se změní barevné mapování.
     */
    @Override
    public void actionPerformed(ActionEvent ae) {
        String command = ae.getActionCommand();
        if (command.equals("Černobílé") || command.equals("Stupně šedi") || command.equals("Barevné spektrum")) {
            imgDisplay.setMapping(command);
        } else {
            imgDisplay.setAxis(command);
        }
        currentAxis = imgDisplay.getCurrentAxis();
    }
}
